处理 JSON
http 400:客户端发送的请求服务器端无法处理
http 405:请求方法不匹配
http 406:服务器端返回的数据客户端无法处理
开启 MVC 驱动
在 SpringMVC 的配置文件中,需要开启 MVC 驱动。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <context:component-scan base-package="com.auguigu"></context:component-scan> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/view/"></property> <property name="suffix" value=".jsp"></property> </bean> <mvc:annotation-driven/> </beans>
|
导入 jar 包
SpringMVC 有自动将 Java 对象转换为 Json 的功能,里面使用的是 jackson,所以需要我们导入相应 jar 包。
1 2 3
| jackson-annotations-2.1.5.jar jackson-core-2.1.5.jar jackson-databind-2.1.5.jar
|
加上 ResponseBody
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| package com.auguigu.test;
import java.util.Collection;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody;
import com.auguigu.bean.Employee; import com.auguigu.dao.EmployeeDao;
@Controller public class TestJsonController { @Autowired private EmployeeDao employeeDao; @RequestMapping("/testJson") @ResponseBody public String testJson() { return "success"; } @RequestMapping("/testJson2") @ResponseBody public Collection<Employee> testJson2() { Collection<Employee> allEmployee = employeeDao.getAll(); return allEmployee; } @RequestMapping(value = "/testJson3", method = RequestMethod.POST) @ResponseBody public Collection<Employee> testJson3() { Collection<Employee> allEmployee = employeeDao.getAll(); return allEmployee; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> </head> <script type="text/javascript" src="${ pageContext.servletContext.contextPath }/js/jquery-1.8.2.min.js"></script> <script type="text/javascript"> $(function(){ $("#btn").click(function(){ $.ajax({ url:"testJson3", type:"POST", data: {}, dataType:"json", success: function(msg){ alert(msg) } }) }) }) </script> <body> <a href="testJson"> 测试 JSON </a> <br/> <a href="testJson2"> 测试 Java Object JSON </a> <br/> <input type="button" id="btn" value="测试 Ajax "/> </body> </html>
|
文件上传/下载
文件上传下载不要求强制记忆,只需会使用就行。
下载
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| package com.auguigu.test;
import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream;
import javax.servlet.http.HttpSession;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping;
@Controller public class TestUploadAndDownController { @RequestMapping(value = "/down") public ResponseEntity<byte []> down(HttpSession session) throws IOException { String fileName = "1.jpg"; String path = session.getServletContext().getRealPath("img"); String finalPath = path + File.separator + fileName; InputStream inputStream = new FileInputStream(finalPath); byte[] body = new byte[inputStream.available()]; inputStream.read(body); HttpHeaders httpHeaders = new HttpHeaders(); httpHeaders.add("Content-Disposition", "attachment;filename=" + fileName); HttpStatus statusCode = HttpStatus.OK; ResponseEntity<byte[]> responseEntity = new ResponseEntity<byte []>(body, httpHeaders, statusCode); return responseEntity; } }
|
上传
SpringMVC 中已经为我们提供了可以上转文件的 MultipartFile,它将客户端上传的 File 文件处理为 MultipartFile。id 的值必须为 multipartResolver。SpringMVC 中的配置文件如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <context:component-scan base-package="com.auguigu"></context:component-scan> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/view/"></property> <property name="suffix" value=".jsp"></property> </bean> <mvc:default-servlet-handler/> <mvc:annotation-driven/>
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="defaultEncoding" value="UTF-8"></property> <property name="maxUploadSize" value="99999999"></property> </bean> </beans>
|
导入 apache commons jar 包
1 2
| commons-fileupload-1.3.1.jar commons-io-2.4.jar
|
保存文件有两种方式,一种是获取输入流,然后创建输出流。另一种是使用 MultipartFile 直接封装好的方法,直接保存文件。两种方式示例如下:
方式1: 通过创建文件输入/输出流
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| @ResponseBody @RequestMapping(value = "/upload1", method = {RequestMethod.POST})
public String upload1(String desc, MultipartFile uploadFile, HttpSession session) throws IOException{ String originalFilename = uploadFile.getOriginalFilename(); String path = session.getServletContext().getRealPath("photo") + File.separator + originalFilename; InputStream inputStream = uploadFile.getInputStream(); File file = new File(path); OutputStream outputStream = new FileOutputStream(file); int i =0; byte[] b = new byte[1024]; while ((i = inputStream.read(b))!=-1) { outputStream.write(b, 0, i); } outputStream.close(); inputStream.close(); return "success";
|
方式1: 通过MultipartFile
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| @ResponseBody @RequestMapping(value = "/upload2", method = {RequestMethod.POST})
public String upload2(String desc, MultipartFile uploadFile, HttpSession session) throws IOException{ String originalFilename = uploadFile.getOriginalFilename(); String finalFileName = UUID.randomUUID().toString().replace("-", "") + originalFilename.substring(originalFilename.lastIndexOf(".")); String path = session.getServletContext().getRealPath("photo") + File.separator + finalFileName; File file = new File(path); uploadFile.transferTo(file); return "success"; }
|
拦截器
概念
Spring MVC也可以使用拦截器对请求进行拦截处理,用户可以自定义拦截器来实现特定的功能,自定义的拦截器可以实现HandlerInterceptor接口,也可以继承 HandlerInterceptorAdapter 适配器类。
注意⚠️:过滤器是请求发送后,先经过过滤器,然后再将请求交给 Servlet 处理,而拦截器是在经过 Servlet 处理后,业务处理器处理请求的时候进行处理。即: 客户端 –> Filter –> DispatcherServlet –> 拦截器 –> Handler(Controller)
preHandle():这个方法在业务处理器处理请求之前被调用,在该方法中对用户请求 request 进行处理。如果程序员决定该拦截器对请求进行拦截处理后还要调用其他的拦截器,或者是业务处理器去进行处理,则返回 true;如果程序员决定不需要再调用其他的组件去处理请求,则返回 false。即返回 true 表示放行,返回 false 表示进行拦截。
postHandle():这个方法在业务处理器处理完请求后,是 DispatcherServlet 向客户端返回响应前被调用,在该方法中对用户请求 request 进行处理。只有正确返回才会调用,如果 Handler 中出错是不会被调用的。
afterCompletion():这个方法在 DispatcherServlet 完全处理完请求后被调用,可以在该方法中进行一些资源清理的操作。不管 Handler 中是否出现错误都会执行。
单个拦截器示例
定义一个 FirstInterceptor 类,并实现 HandlerInterceptor 接口。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| package com.auguigu.interceptor;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView;
@Component public class FirstInterceptor implements HandlerInterceptor{
@Override public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)throws Exception { System.out.println("afterCompletion, 相当于在 finally 里面,无论失败成功都会执行"); }
@Override public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)throws Exception { System.out.println("postHandle, 正确的返回之后之后才会执行,位置相当于在 ModelAndView 之后"); }
@Override public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception { System.out.println("preHandle,Handler 开始处理请求之前"); return true; } }
|
在 SpringMVC 配置文件中应用该拦截器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <context:component-scan base-package="com.auguigu"></context:component-scan> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/view/"></property> <property name="suffix" value=".jsp"></property> </bean> <mvc:default-servlet-handler/> <mvc:annotation-driven/>
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="defaultEncoding" value="UTF-8"></property> <property name="maxUploadSize" value="99999999"></property> </bean> <mvc:interceptors> <ref bean="firstInterceptor"/> </mvc:interceptors> </beans>
|
新建 Controller 进行测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| package com.auguigu.test;
import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody;
@Controller public class TestInterceptorController { @ResponseBody @RequestMapping(value = "/testInterceptor") public String testInterceptor() { return "success"; } }
|
输出内容
1 2 3
| preHandle,Handler 开始处理请求之前 postHandle, 正确的返回之后之后才会执行,位置相当于在 ModelAndView 之后 afterCompletion, 相当于在 finally 里面,无论失败成功都会执行
|
自定义拦截方式
我可以可以针对某些请求进行拦截。并不是上面例子中的拦截所有。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <mvc:interceptors> <ref bean="firstInterceptor"/> <mvc:interceptor> <bean></bean> <mvc:mapping path=""/> <mvc:exclude-mapping path=""/> </mvc:interceptor> </mvc:interceptors>
|
例子
1 2 3 4 5 6 7 8 9 10 11 12
| <mvc:interceptors>
<bean id="firstHandlerInterceptor" class="com.atguigu.springmvc.interceptors.FirstHandlerInterceptor"></bean>
<mvc:interceptor> <mvc:mapping path="/empList"/>
<bean id="secondHandlerInterceptor" class="com.atguigu.springmvc.interceptors.SecondHandlerInterceptor"></bean> </mvc:interceptor> </mvc:interceptors>
|
多个拦截器执行顺序
当有多个拦截器时,如果多个拦截器的 preHandle 方法返回的都是 true 时,preHandle 的执行顺序是按照拦截器配置顺序正向执行的。postHandle 和 afterCompletion 是按照拦截器拦截器配置顺序反向执行的。
当有多个拦截器时,如果多个拦截器的 preHandle 方法返回都是 false,那么只有第一个拦截器的 preHandle 会被执行。
当有两个(多个)拦截器时,如果第一个拦截器的 preHandle 方法返回的是 true,第二个拦截器的 preHandle 方法返回 false。那么两个(多个)拦截器的 preHandle 方法都会执行,但是 postHandle 都不会执行。afterCompletion 只有第一个(返回 false 的拦截器之前的所有拦截器)拦截器执行。
当有多个拦截器时,如果第一个拦截器的 preHandle 方法返回的是 false,第二个拦截器的 preHandle 方法返回 true。这时只有第一个拦截器的 preHandle 会执行。
代码地址